/* 
 * File:   BooleanFunction.h
 * Author: sergey
 *
 * Created on 3 Декабрь 2009 г., 20:24
 */

#ifndef _BOOLEANFUNCTION_H
#define	_BOOLEANFUNCTION_H
#include "LibraryInterface.h"

/*
 * Ниже описывается две шаблонных структуры, которые создают предпосчитанные
 * значения масок для векторов функций.
 * AttributeMaskRepeater - структура для повторения бинарных кусков A T раз
 * длины L.
 */
template <UInt64 A, UInt64 T, UInt64 L>
struct AttributeMaskRepeater { enum {value = (static_cast<UInt64>(AttributeMaskRepeater<A, T - 1, L>::value) << L) + A}; };
template <UInt64 A, UInt64 L>
struct AttributeMaskRepeater<A,static_cast<UInt64>(1),L> { enum {value = A}; };
/* Структура для генерации масок вектора функции класса LIBINFO по V-му аргументу */
template <typename LIBINFO, int V>
struct AttributeMask {
    enum {
        repeater = ((static_cast<UInt64>(1) << (LIBINFO::aC >> (V + 1))) - 1) << (LIBINFO::aC >> (V + 1)),
        times = static_cast<UInt64>(1) << V,
        length = (LIBINFO::aC >> (V + 1)) << 1,
        value = AttributeMaskRepeater<repeater,times,length>::value
    };
};

template<UInt64 n>
struct filled_mask {
    static const UInt64 value = (1ULL << n) - 1;
};

/*
 * Класс BooleanFunction используется для хранения булевой функции и для
 * lp-операций над ними.
 */
template <typename LIBINFO>
class BooleanFunction {
public:
    UInt64 f;
    BooleanFunction() {f = 0;}
    BooleanFunction(UInt64 f) {this->f = f;}
    ~BooleanFunction() { }
    // транспозиция переменных в функции
    template<int va, typename INT>
    inline static void transposition(INT &f) {

        enum {
            sm = AttributeMask<LIBINFO, (va + 1) % LIBINFO::n>::value ^ AttributeMask<LIBINFO, va>::value,
            _apm = sm & AttributeMask<LIBINFO, (va + 1) % LIBINFO::n>::value,
            _bpm = sm & ~AttributeMask<LIBINFO, (va + 1) % LIBINFO::n>::value,
            sd1 = (1 << (LIBINFO::n - va)) >> 1,
            sd2 = (1 << (LIBINFO::n - (va + 1) % LIBINFO::n)) >> 1,
            sd =  sd1 > sd2 ? sd1 - sd2 : sd2 - sd1,
            apm = sd1 > sd2 ? _apm : _bpm,
            bpm = sd1 > sd2 ? _bpm : _apm,
            neg_sm = ~sm
        };
        
        f = (f & neg_sm) ^ ((f & apm) << sd) ^ ((f & bpm) >> sd);
    }

    // отрицание переменной в функции
    template<int va, typename INT>
    inline static void negation(INT &f){
        enum {
            sd = 1 << (LIBINFO::n - va - 1)
        };
        f = ((f & AttributeMask<LIBINFO,va>::value) >> sd) ^ ((f & ~AttributeMask<LIBINFO,va>::value) << sd);
    }

    // производная x0 - d
    template<int va, typename INT> 
    inline static void derivative1(INT &f) {
        enum {
            sd = 1 << (LIBINFO::n - va - 1)
        };
        f = ((f & AttributeMask<LIBINFO, va>::value)) 
                ^ ((f & AttributeMask<LIBINFO, va>::value)>>sd) ^ ((f & ~AttributeMask<LIBINFO, va>::value));
    }

    // производная d - x0
    template<int va, typename INT> 
    inline static void derivative2(INT &f) {
        enum {
            sd = 1 << (LIBINFO::n - va - 1)
        };
        f = ((f & AttributeMask<LIBINFO,va>::value) >> sd) 
                ^ ((f & AttributeMask<LIBINFO,va>::value)) ^ ((f & ~AttributeMask<LIBINFO,va>::value) << sd);
    }

    // производная x1 - d
    template<int va, typename INT> 
    inline static void derivative3(INT &f) {
        enum {
            sd = 1 << (LIBINFO::n - va - 1)            
        };
        f =  ((f & ~AttributeMask<LIBINFO,va>::value) << sd) 
                ^ ((f & AttributeMask<LIBINFO,va>::value)>>sd) ^ ((f & ~AttributeMask<LIBINFO,va>::value));

    }

    // производная d - x1
    template<int va, typename INT>
    inline static void derivative4(INT &f) {
        enum {
            sd = 1 << (LIBINFO::n - va - 1) 
        };
        f = ((f & ~AttributeMask<LIBINFO,va>::value)) 
                ^ ((f & AttributeMask<LIBINFO,va>::value)) ^ ((f & ~AttributeMask<LIBINFO,va>::value) << sd);
    }
private:

};

#endif	/* _BOOLEANFUNCTION_H */

